package main

import (
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"fmt"
	pb "github.com/hyperledger/fabric/protos/peer"
	"errors"
	"bytes"
	"strconv"
	"encoding/json"
	"time"
	"strings"
	"math/big"
)

type AccountChaincode struct {
} 

type Account struct {
	Addr		string 				`json:"addr"`
	Balance 	map[string]*big.Int	`json:"balance"`
	Nonce   	int 				`json:"nonce"`
	IsToken		bool 				`json:"isToken"`
}

var log *shim.ChaincodeLogger

func main() {
	err := shim.Start(new(AccountChaincode))
	if err != nil {
		fmt.Errorf(err.Error())
	}
}

func (t AccountChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {

	return shim.Success(nil)
}

func (t AccountChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

	fnc, args := stub.GetFunctionAndParameters()

	log = getLogger(stub)

	if fnc == "" {
		return shim.Success(SysFail("function is nil"))
	} else if fnc == "transfer" { // 发起转账					success
		return t.Transfer(stub, args)
	} else if fnc == "exchange" {						// 兑换（众筹）
		return t.Exchange(stub, args)
	} else if fnc == "getAccount" {						// 获取账户信息				success
		return t.GetAccount(stub, args)
	} else if fnc == "getAccountHis" {					// 获取账户历史				success
		return t.GetAccountHis(stub, args)
	} else if fnc == "lockToken" {						// 锁定代币					success
		return t.LockToken(stub, args)
	} else if fnc == "balance" {						// 余额						success
		return t.Balance(stub, args)
	} else if fnc == "lockTokenAccount" {				// 锁定代币中的用户			success
		return t.LockTokenAccount(stub, args)
	} else if fnc == "unLockTokenAccount" {				// 解锁用户					success
		return t.UnLockTokenAccount(stub, args)
	} else if fnc == "newAccount" {						// 新建账户					success
		return t.NewAccount(stub, args)
	} else if fnc == "getNonce" {						// 获取nonce					success
		return t.GetNonce(stub, args)
	} else if fnc == "mint" {							// 增发代币					success
		return t.Mint(stub, args)
	} else if fnc == "burn" {							// 回收代币					success
		return t.Burn(stub, args)
	} else if fnc == "setOwner" {						// 设置所有人					success
		return t.SetOwner(stub, args)
	} else if fnc == "queryAddresses" {					// 获取拥有代币用户
		return t.QueryAddresses(stub, args)
	} else if fnc == "addCrowfund" {					// 发起众筹
		return t.AddCrowfund(stub, args)
	} else if fnc == "recharge" {						// 充值
		return t.Recharge(stub, args)
	} else if fnc == "addToken" {						// 添加代币
		return t.AddToken(stub, args)
	}

	return shim.Success(SysFail("function is nil"))
}

func (t AccountChaincode) NewAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	addr := has0xSuf(args[0])
	account := &Account{
		Addr:    addr,
		Balance: make(map[string]*big.Int),
		Nonce:   0,
	}
	err := setAccount(stub, *account)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	return shim.Success(Ok(addr).ToByte())
}

type Transaction struct {
	Nonce  	int 		`json:"nonce"`
	Token   string 		`json:"token"`
	To		string 		`json:"to"`
	Value   *big.Int 	`json:"value"`
	Data	[]byte 		`json:"data"`
}

type RecordTransaction struct {
	Transaction
	From 	string `json:"from"`
	Sign	[]byte `json:"sign"`
	Hash    []byte `json:"hash"`
}

func (t AccountChaincode) Transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	log.Info(args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}

	// 获取参数
	//tokenName, to, valueStr, nonceStr, sign, data := args[0], args[1], args[2], args[3], args[4], args[5]
	//tokenName, to = tokenName, has0xSuf(from), has0xSuf(to)

	transByte := []byte(args[0])
	var transaction RecordTransaction
	err := json.Unmarshal(transByte, &transaction)
	if err == nil {
		if transaction.Token == "" {
			return shim.Success(tokenNilErr)
		}
		if transaction.To == "" {
			return shim.Success(addrNilErr)
		}
		// 检查value长度
		if !checkValue(*transaction.Value) {
			return shim.Success(valueErr)
		}
	} else {
		//logger.Error(err)
		return shim.Success(SysFail(err.Error()))
	}

	//
	//	新版本功能代码 BEGIN
	//

	// 将原有参数进行hash
	msgByte, _ := json.Marshal(transaction.Transaction)
	log.Infof("msgByte: %s", string(msgByte))
	msgHash := Keccak256(msgByte)
	transaction.Hash = msgHash
	log.Infof("msg hash: %s", ToHex(msgHash))

	// 验证交易信息，并从交易签名中恢复交易发起人地址
	from, bs := verifyTransaction(msgHash, transaction.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}
	transaction.From = from
	transaction.Token = strings.ToLower(transaction.Token)
	log.Infof("get from addr: %s", from)

	//
	//	新版本功能代码 END
	//

	transaction.To = has0xSuf(transaction.To)

	// 判定 from 和 to 的关系
	if from == transaction.To {
		return shim.Success(valueErr)
	}

	log.Debugf("transaction.nonce: %d", transaction.Nonce)
	log.Debugf("transaction.Token: %s", string(transaction.Token))
	log.Debugf("transaction.To: %s", string(transaction.To))
	log.Debugf("transaction.Value: %s", string(transaction.Value.String()))


	// 获取账户信息
	accountFrom, err := getAccount(stub, transaction.From)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Info("获取from信息成功", accountFrom)

	accountTo, err := getAccount(stub, transaction.To)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Info("获取to信息成功", accountTo)

	// 判断账户锁定
	token, err := getToken(stub, transaction.Token)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Info("获取token信息成功", token)
	if token.Lock {
		return shim.Success(tokenLockErr)
	}
	if token.LockAccount[transaction.From] || token.LockAccount[transaction.To] {
		return shim.Success(accountLockErr)
	}

	// 判断账户余额
	if accountFrom.Balance == nil || accountFrom.Balance[transaction.Token] == nil {
		return shim.Success(balanceErr)
	}
	if accountFrom.Balance[transaction.Token].Cmp(transaction.Value) == -1 {
		return shim.Success(balanceErr)
	}

	// 判断nonce
	if transaction.Nonce - accountFrom.Nonce != 1 {
		return shim.Success(nonceError)
	}

	if accountFrom.Balance == nil {
		accountFrom.Balance = make(map[string]*big.Int)
	}
	if accountTo.Balance == nil {
		accountTo.Balance = make(map[string]*big.Int)
	}

	// 开始修改数据
	accountFrom.Balance[transaction.Token].Sub(accountFrom.Balance[transaction.Token], transaction.Value)
	accountFrom.Nonce += 1

	log.Infof("对比from数据： %v", accountFrom)
	log.Infof("对比*from数据： %v", *accountFrom)

	if accountTo.Balance[transaction.Token] == nil {
		accountTo.Balance[transaction.Token] = new(big.Int).Set(transaction.Value)
	} else {
		accountTo.Balance[transaction.Token].Add(accountTo.Balance[transaction.Token], transaction.Value)
	}

	// 写入数据
	err = setAccount(stub, *accountFrom)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	err = setAccount(stub, *accountTo)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 记录交易
	tb, err := json.Marshal(transaction)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if err = recordTransaction(stub, transaction.From, tb); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

type InitToken struct {
	Name string `json:"name"`
	Symbol string `json:"symbol"`
	Suply *big.Int `json:"suply"`
}

type InitTokenSign struct {
	InitToken
	Owner string `json:"owner"`
	Sign []byte `json:"sign"`
	Hash []byte `json:"hash"`
}

func (t AccountChaincode) AddToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	log.Infof("args: %s", args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	// 解析数据结构
	var initTokenSign InitTokenSign
	if err := json.Unmarshal([]byte(args[0]), &initTokenSign); err != nil {
		return shim.Success(parameterErr)
	} else {
		if initTokenSign.Name == "" || initTokenSign.Symbol == "" || initTokenSign.Sign == nil {
			return shim.Success(parameterErr)
		}
	}

	// 验证签名（校验签名之前不要动原本的请求结构）
	hash, _ := json.Marshal(initTokenSign.InitToken)
	msgHash := Keccak256(hash)
	initTokenSign.Hash = msgHash

	from, bs := verifyTransaction(msgHash, initTokenSign.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}

	// 名称转小写
	initTokenSign.Symbol = strings.ToLower(initTokenSign.Symbol)

	// 校验代币名称是否重复
	_, err := queryTokenIsExist(stub, initTokenSign.Symbol)
	if err != nil {
		return shim.Success(SysFail("通证已存在或通证列表异常，请联系管理员"))
	}

	// 检测指定账户是否已经创建过代币
	mytoken, err := queryTokenList(stub, from)
	if err != nil {
		return shim.Success(SysFail("查询通证列表异常"))
	}
	if mytoken != nil {
		return shim.Success(addrInTokenErr)
	}

	initTokenSign.Owner = from

	// 给自己记账
	fromAccount, err := getAccount(stub, from)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if fromAccount.Balance == nil {
		fromAccount.Balance = make(map[string]*big.Int)
	}
	fromAccount.Balance[initTokenSign.Symbol] = initTokenSign.Suply
	fromAccount.Nonce += 1
	fromAccount.IsToken = true

	// 保存数据
	err = setAccount(stub, *fromAccount)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 通知tokenList
	tokenListTrans := [][]byte{[]byte("add"), []byte(initTokenSign.Name), []byte(initTokenSign.Symbol),
		[]byte(initTokenSign.Suply.String()), []byte(initTokenSign.Owner)}
	_, err = invokeChaincode(stub, "tokenList", tokenListTrans)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 记录流水
	trans := RecordTransaction{
		Transaction: Transaction{
			Nonce: fromAccount.Nonce,
			Token: initTokenSign.Symbol,
			To:    fromAccount.Addr,
			Value: initTokenSign.Suply,
			Data:  []byte(initTokenSign.Name),
		},
		From: initTokenSign.Owner,
		Sign: initTokenSign.Sign,
		Hash: initTokenSign.Hash,
	}
	tb, err := json.Marshal(trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if err = recordTransaction(stub, trans.From, tb); err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	return shim.Success(SUCCESS)
}

// 查询我的代币信息
func queryTokenIsExist(stub shim.ChaincodeStubInterface, symbol string) ([]byte, error) {
	trans := [][]byte{[]byte("isExist"), []byte(symbol)}
	return invokeChaincode(stub, "tokenList", trans)
}

type BaseCrowFund struct {
	Nonce int `json:"nonce"`
	CreateTime  int64	 	`json:"createTime"`			// 创建时间

	TargetToken	string 		`json:"targetToken"`			// 所需币种

	SourceToken	string		`json:"sourceToken"`			// 众筹币种
	SourceNum   *big.Int		`json:"sourceNum"`			// 众筹额度

	EndTime		int64		`json:"endTime"`			// 结束时间
}

type CrowFund struct {
	BaseCrowFund
	Owner string `json:"owner"`
	Sign  []byte `json:"sign"`
	Hash  []byte `json:"hash"`
}

// TODO 流程还未完善
func (t AccountChaincode) AddCrowfund(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	log.Infof("args: %s", args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}

	// 解析参数
	var crowfund CrowFund
	if err := json.Unmarshal([]byte(args[0]), &crowfund); err != nil {
		return shim.Success(SysFail(err.Error()))
	} else {
		if crowfund.CreateTime == 0 || crowfund.EndTime == 0 || crowfund.EndTime <= crowfund.CreateTime {
			return shim.Success(Fail(40003, "crowfund time error").ToByte())
		}
		if crowfund.TargetToken == "" {
			return shim.Success(Fail(40004, "targetToken is nil").ToByte())
		}
		if crowfund.SourceToken == "" {
			return shim.Success(Fail(40005, "sourcetoken is nil").ToByte())
		}
		if crowfund.SourceNum.Cmp(new(big.Int)) <= 0 {
			return shim.Success(Fail(40006, "sourcenum error").ToByte())
		}
	}

	// 对原始数据进行hash
	hb, _ := json.Marshal(crowfund.BaseCrowFund)
	msgHash := Keccak256(hb)
	crowfund.Hash = msgHash

	// 验证消息准确性，并提取交易发起人地址
	from, bs := verifyTransaction(msgHash, crowfund.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}
	crowfund.Owner = from
	// 涉及代币名称转小写
	crowfund.SourceToken = strings.ToLower(crowfund.SourceToken)
	crowfund.TargetToken = strings.ToLower(crowfund.TargetToken)

	log.Infof("crowfund: %s", crowfund)

	// 提取交易发起人信息
	accountFrom, err := getAccount(stub, from)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Infof("get from: %s", accountFrom)
	// 判断nonce
	if crowfund.Nonce - accountFrom.Nonce != 1 {
		return shim.Success(nonceError)
	}
	// 判断余额
	if accountFrom.Balance[crowfund.SourceToken] == nil || accountFrom.Balance[crowfund.SourceToken].Cmp(crowfund.SourceNum) < 0 {
		return shim.Success(balanceErr)
	}

	// 发起交易请求
	cb, _ := json.Marshal(crowfund)
	trans := [][]byte{[]byte("add"), cb}
	_, err = invokeChaincode(stub, "crowfund", trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 扣减自己的余额
	accountFrom.Balance[crowfund.SourceToken].Sub(accountFrom.Balance[crowfund.SourceToken], crowfund.SourceNum)
	accountFrom.Nonce += 1

	// 保存数据
	if err := setAccount(stub, *accountFrom); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 记录转账信息
	key, err := stub.CreateCompositeKey(from, []string{crowfund.TargetToken, crowfund.SourceToken})
	transaction := RecordTransaction{
		Transaction: Transaction{
			Nonce: crowfund.Nonce,
			Token: crowfund.SourceToken,
			To:    key,
			Value: crowfund.SourceNum,
			Data:  nil,
		},
		From: from,
		Sign: crowfund.Sign,
		Hash: crowfund.Hash,
	}
	tb, _ := json.Marshal(transaction)
	if err := recordTransaction(stub, from, tb); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

type ExchangeTransaction struct {
	Nonce 			int 		`json:"nonce"`
	To     			string 		`json:"to"`
	MainToken 		string 		`json:"mainToken"`
	MainValue  		*big.Int	`json:"mainValue"`
	ExchangeToken 	string 		`json:"exchangeToken"`
	ExchangeValue 	*big.Int	`json:"exchangeValue"`
}

type CrowExchangeTrans struct {
	ExchangeTransaction
	From string `json:"from"`
	Hash []byte `json:"hash"`
	Sign []byte `json:"sign"`
}

func (t AccountChaincode) Exchange(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	log.Infof("invoke exchange, args: %s", args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}

	// 获取参数
	// nonceStr, to, mainToken, mainValue, exchangeToken, exchangeValue

	exTransByte := []byte(args[0])
	var exTrans CrowExchangeTrans
	err := json.Unmarshal(exTransByte, &exTrans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	} else {
		// 判断参数并将部分参数转小写操作
		if exTrans.To == "" {
			return shim.Success(Fail(40007, "兑换目标地址为空").ToByte())
		}
		if exTrans.MainToken == "" {
			return shim.Success(Fail(40008, "兑换主币为空").ToByte())
		}
		if exTrans.ExchangeToken == "" {
			return shim.Success(Fail(40009, "兑换币为空").ToByte())
		}
		if !checkValue(*exTrans.MainValue) || !checkValue(*exTrans.ExchangeValue) {
			return shim.Success(valueErr)
		}
	}



	// 对原始交易进行hash
	hb, _ := json.Marshal(exTrans.ExchangeTransaction)
	msgHash := Keccak256(hb)
	exTrans.Hash = msgHash

	from, bs := verifyTransaction(msgHash, exTrans.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}

	exTrans.From = from
	// 源数据处理
	exTrans.To = has0xSuf(exTrans.To)
	exTrans.MainToken = strings.ToLower(exTrans.MainToken)
	exTrans.ExchangeToken = strings.ToLower(exTrans.ExchangeToken)

	log.Infof("get from: %s", from)

	// 校验地址合法性
	if !checkAddress(exTrans.To) {
		return shim.Success(addressError)
	}

	// 获取数据
	accountFrom, err := getAccount(stub, from)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	accountTo, err := getAccount(stub, exTrans.To)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	mainToken, err := getToken(stub, exTrans.MainToken)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	exchangeToken, err := getToken(stub, exTrans.ExchangeToken)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 判断条件
	if exTrans.Nonce - accountFrom.Nonce != 1 {
		return shim.Success(nonceError)
	}
	if mainToken.Lock {
		return shim.Success(tokenLockErr)
	}
	if exchangeToken.Lock {
		return shim.Success(tokenLockErr)
	}
	if mainToken.LockAccount[accountFrom.Addr] || mainToken.LockAccount[accountTo.Addr] ||
		exchangeToken.LockAccount[accountFrom.Addr] || exchangeToken.LockAccount[accountTo.Addr] {
		return shim.Success(accountLockErr)
	}
	// 在进行兑换操作时，只需要判定转出方余额就可以
	if accountFrom.Balance[mainToken.Symbol].Cmp(exTrans.MainValue) < 0 {
		return shim.Success(balanceErr)
	}

	// 发起众筹请求																									1
	//crowExc := CrowExchangeTrans{
	//	ExchangeTransaction: exTrans,
	//	From: from,
	//}
	cb, err := json.Marshal(exTrans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	trans := [][]byte{[]byte("exchange"), cb}
	_, err = invokeChaincode(stub, "crowfund", trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	accountFrom.Nonce += 1

	// 增加自己的众筹币（如果是交易主币，肯定不会空；如果是众筹币，交易发起方不一定有，会npe								2
	if accountFrom.Balance[exchangeToken.Symbol] == nil {
		accountFrom.Balance[exchangeToken.Symbol] = new(big.Int)
	}
	accountFrom.Balance[exchangeToken.Symbol].Add(accountFrom.Balance[exchangeToken.Symbol], exTrans.ExchangeValue)

	// 扣减主币																										3
	accountFrom.Balance[mainToken.Symbol].Sub(accountFrom.Balance[mainToken.Symbol], exTrans.MainValue)

	// 保存数据																										4
	if err = setAccount(stub, *accountFrom); err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if err = setAccount(stub, *accountTo); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 保存记录
	key, _ := stub.CreateCompositeKey(exTrans.To, []string{exTrans.MainToken, exTrans.ExchangeToken})
	transaction := RecordTransaction{
		Transaction: Transaction{
			Nonce: exTrans.Nonce,
			Token: exTrans.MainToken,
			To:    key,
			Value: exTrans.MainValue,
			Data:  nil,
		},
		From: exTrans.From,
		Sign: exTrans.Sign,
		Hash: exTrans.Hash,
	}
	tb, err := json.Marshal(transaction)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if err = recordTransaction(stub, accountFrom.Addr, tb); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

type Recharge struct {
	Nonce int `json:"nonce"`
	To string `json:"to"`
	Rmb *big.Int `json:"rmb"`
	Vcc *big.Int `json:"vcc"`
	Data []byte `json:"data"`
}

type RechargeTrans struct {
	Recharge
	From string `json:"from"`
	Hash []byte `json:"hash"`
	Sign []byte `json:"sign"`
}

var rmb, vcc = "rmb", "vcc"

func (t AccountChaincode) Recharge(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	log.Info(args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	var recharge RechargeTrans
	err := json.Unmarshal([]byte(args[0]), &recharge)
	if err != nil {
		return shim.Success(parameterErr)
	} else {
		if recharge.To == "" {
			return shim.Success(Fail(40002, "transaction addr is nil").ToByte())
		}
		if !checkValue(*recharge.Rmb) || !checkValue(*recharge.Vcc) {
			return shim.Success(valueErr)
		}
	}

	// 开始验证签名
	hb, _ := json.Marshal(recharge.Recharge)
	log.Debugf("msg hashes: %s", string(hb))
	hash := Keccak256(hb)
	from, bs := verifyTransaction(hash, recharge.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}

	// 获取转出方账户信息
	fromAccount, err := getAccount(stub, from)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Debugf("get from account: %s", fromAccount)

	// 获取转入方账户信息
	toAccount, err := getAccount(stub, recharge.To)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Debugf("get to account: %s", toAccount)

	// 获取代币信息
	rmbToken, err := getToken(stub, rmb)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	vccToken, err := getToken(stub, vcc)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 检查nonce
	if recharge.Nonce - fromAccount.Nonce != 1 {
		return shim.Success(nonceError)
	}

	// 判断锁定及余额情况
	if rmbToken.Lock {
		return shim.Success(rmbTokenLock)
	}
	if vccToken.Lock {
		return shim.Success(vccTokenLock)
	}
	if rmbToken.LockAccount[from] || vccToken.LockAccount[from] {
		return shim.Success(fromAccountLock)
	}
	if rmbToken.LockAccount[recharge.To] || vccToken.LockAccount[recharge.To] {
		return shim.Success(toAccountLock)
	}

	// 判断转出方余额
	if fromAccount.Balance[rmb].Cmp(recharge.Rmb) < 0 {
		return shim.Success(rmbBalanceErr)
	}
	if fromAccount.Balance[vcc].Cmp(recharge.Vcc) < 0 {
		return shim.Success(vccBalanceErr)
	}

	// 开始操作数据
	// 转出
	fromAccount.Nonce += 1
	fromAccount.Balance[rmb].Sub(fromAccount.Balance[rmb], recharge.Rmb)
	fromAccount.Balance[vcc].Sub(fromAccount.Balance[vcc], recharge.Vcc)

	// 转入
	if toAccount.Balance[rmb] == nil {
		toAccount.Balance[rmb] = recharge.Rmb
	} else {
		toAccount.Balance[rmb].Add(toAccount.Balance[rmb], recharge.Rmb)
	}
	if toAccount.Balance[vcc] == nil {
		toAccount.Balance[vcc] = recharge.Vcc
	} else {
		toAccount.Balance[vcc].Add(toAccount.Balance[vcc], recharge.Vcc)
	}

	// 写入数据
	if err := setAccount(stub, *fromAccount); err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if err := setAccount(stub, *toAccount); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 记录
	record := &RecordTransaction{
		Transaction: Transaction{
			Nonce: recharge.Nonce,
			Token: vcc,
			To:    recharge.To,
			Value: recharge.Vcc,
			Data:  recharge.Data,
		},
		From: from,
		Sign: recharge.Sign,
		Hash: recharge.Hash,
	}
	rb, _ := json.Marshal(record)
	if err := recordTransaction(stub, from, rb); err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

// TODO 增发代币是否需要记录transaction ？ 需要记录，否则拥有签名数据后，可以无限增发，使用nonce进行防重操作
func (t AccountChaincode) Mint(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	log.Debug(args)
	if len(args) != 4 {
		return shim.Success(parameterErr)
	}
	token, addr, valueStr, nonceStr := strings.ToLower(args[0]), has0xSuf(args[1]), args[2], args[3]
	value, err := strconv.ParseInt(valueStr, 10, 64)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	nonce, err := strconv.Atoi(nonceStr)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	// 获取数据
	account, err := getAccount(stub, addr)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Debugf("get account: %s", account)

	// 判断nonce
	if nonce - account.Nonce != 1 {
		return shim.Success(nonceError)
	}
	// 修改数据
	account.Nonce ++
	if account.Balance[token] == nil {
		account.Balance[token] = new(big.Int).SetInt64(value)
	} else {
		account.Balance[token].Add(account.Balance[token], new(big.Int).SetInt64(value))
	}

	trans := [][]byte{[]byte("mint"), []byte(addr), []byte(valueStr)}
	_, err = invokeChaincode(stub, token, trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	// 写入数据
	err = setAccount(stub, *account)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

func (t AccountChaincode) Burn(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 4 {
		return shim.Success(parameterErr)
	}

	token, addr, valueStr, nonceStr := strings.ToLower(args[0]), has0xSuf(args[1]), args[2], args[3]
	value, err := strconv.ParseInt(valueStr, 10, 64)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	nonce, err := strconv.Atoi(nonceStr)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	// 获取数据
	account, err := getAccount(stub, addr)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 判断nonce
	if nonce-account.Nonce != 1 {
		return shim.Success(nonceError)
	}
	// 判断余额
	if account.Balance[token] == nil || account.Balance[token].Int64() < value {
		return shim.Success(valueErr)
	}
	// 修改数据
	account.Nonce ++
	account.Balance[token].Sub(account.Balance[token], new(big.Int).SetInt64(value))

	trans := [][]byte{[]byte("burn"), []byte(addr), []byte(valueStr)}
	_, err = invokeChaincode(stub, token, trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	err = setAccount(stub, *account)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

func (t AccountChaincode) SetOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 3 {
		return shim.Success(parameterErr)
	}
	token, from, to := strings.ToLower(args[0]), has0xSuf(args[1]), has0xSuf(args[2])

	// 直接去修改合约数据
	trans := [][]byte{[]byte("setOwner"), []byte(from), []byte(to)}
	_, err := invokeChaincode(stub, token, trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// TODO 修改所有人是否需要通知TokenList

	return shim.Success(SUCCESS)
}

func (t AccountChaincode) LockToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	log.Infof("请求参数列表： %s", args)
	if len(args) != 3 {
		return shim.Success(parameterErr)
	}
	log.Info("开始锁定通证合约：")
	token, key, b := strings.ToLower(args[0]), has0xSuf(args[1]), args[2]

	var fnc string
	lock, err := strconv.ParseBool(b)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Info(lock)
	if lock {
		fnc = "lockToken"
	} else {
		fnc = "unLockToken"
	}
	log.Info(fnc)

	trans := [][]byte{[]byte(fnc), []byte(key)}
	res, err := invokeChaincode(stub, token, trans)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	return shim.Success(Ok(string(res)).ToByte())
}

type LocAcc struct {
	Nonce int `json:"nonce"`
	Token string `json:"token"`
	Addr string `json:"addr"`
	Data []byte `json:"data"`
}

type LocAccTrans struct {
	LocAcc
	From string `json:"from"`
	Hash []byte `json:"hash"`
	Sign []byte `json:"sign"`
}

func (t AccountChaincode) LockTokenAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return lockTokenAccount(stub, args, true)
}

func (t AccountChaincode) UnLockTokenAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return lockTokenAccount(stub, args, false)
}

func lockTokenAccount(stub shim.ChaincodeStubInterface, args []string, b bool) pb.Response {

	log.Info(args)
	if len(args) != 1 {
		return shim.Success(parameterErr)
	}

	//token, key, to, b := args[0], has0xSuf(args[1]), has0xSuf(args[2]), args[3]

	lockByte := []byte(args[0])
	var locAccTrans LocAccTrans
	if err := json.Unmarshal(lockByte, &locAccTrans); err != nil {
		return shim.Success(parameterErr)
	}

	// 校验hash以及签名
	hb, _ := json.Marshal(locAccTrans.LocAcc)
	log.Infof("message byte: %s", string(hb))

	msgHash := Keccak256(hb)
	locAccTrans.Hash = msgHash
	addr, bs := verifyTransaction(msgHash, locAccTrans.Sign)
	if !bs {
		return shim.Success(verifyKeyErr)
	}
	locAccTrans.From = addr
	locAccTrans.Token = strings.ToLower(locAccTrans.Token)

	log.Debugf("get from addr: %s", addr)

	// 获取fromAcc
	fromAccount, err := getAccount(stub, locAccTrans.From)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Infof("get fromAccount: %v", fromAccount)

	// 判断nonce
	if locAccTrans.Nonce - fromAccount.Nonce != 1 {
		return shim.Success(nonceError)
	}

	// 获取该账户名下的token
	token, err := getToken(stub, locAccTrans.Token)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	log.Infof("get token: %v", token)

	err = lockAccount(stub, locAccTrans.From, locAccTrans.Addr, token.Symbol, b)
	if err != nil {
		log.Errorf("lock account error: %s", err.Error())
		return shim.Success(SysFail(err.Error()))
	}

	// 操作成功后，修改账户的nonce
	fromAccount.Nonce += 1

	// 保存数据
	err = setAccount(stub, *fromAccount)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	record := RecordTransaction{
		Transaction: Transaction{
			Nonce: locAccTrans.Nonce,
			Token: locAccTrans.Token,
			To:    locAccTrans.Addr,
			Value: &big.Int{},
			Data:  locAccTrans.Data,
		},
		From: locAccTrans.From,
		Sign: locAccTrans.Sign,
		Hash: locAccTrans.Hash,
	}
	rb, err := json.Marshal(&record)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	err = recordTransaction(stub, record.From, rb)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(SUCCESS)
}

func lockAccount(stub shim.ChaincodeStubInterface, from, to, token string, isLock bool) error {

	fnc := ""
	if isLock {
		fnc = "lockAccount"
	} else {
		fnc = "unLockAccount"
	}

	trans := [][]byte{[]byte(fnc), []byte(from), []byte(to)}
	_, err := invokeChaincode(stub, token, trans)
	if err != nil {
		return err
	}

	return nil
}

func (t AccountChaincode) GetNonce(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 || args[0] == "" {
		return shim.Success(parameterErr)
	}
	addr := has0xSuf(args[0])
	account, err := getAccount(stub, addr)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(Ok(strconv.Itoa(account.Nonce + 1)).ToByte())
}

func (t AccountChaincode) Balance(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Success(parameterErr)
	}

	token, key := strings.ToLower(args[0]), has0xSuf(args[1])

	ab, err := stub.GetState(key)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	var account Account
	if ab == nil {
		// 当账户数据不存在时，初始化账户数据
		account.Addr = key
		account.Balance = make(map[string]*big.Int)
		account.IsToken = false
		account.Nonce = 0
	} else {
		err = json.Unmarshal(ab, &account)
		if err != nil {
			return shim.Success(SysFail(err.Error()))
		}
	}

	if account.Balance == nil {
		account.Balance = make(map[string]*big.Int)
	}
	if !account.IsToken {
		err = addToken(stub, &account)
		if err != nil {
			return shim.Success(SysFail(err.Error()))
		}
	}

	if account.Balance[token] == nil {
		return shim.Success(Ok("0").ToByte())
	} else {
		return shim.Success(Ok(account.Balance[token].String()).ToByte())
	}
}


func (t AccountChaincode) GetAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	key := has0xSuf(args[0])
	ab, err := stub.GetState(key)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	var account Account
	if ab == nil {
		// 当账户数据不存在时，初始化账户数据
		account.Addr = key
		account.Balance = make(map[string]*big.Int)
		account.IsToken = false
		account.Nonce = 0
	} else {
		err = json.Unmarshal(ab, &account)
		if err != nil {
			return shim.Success(SysFail(err.Error()))
		}
	}

	err = queryMyToken(stub, &account)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	ab, err = json.Marshal(account)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(Ok(string(ab)).ToByte())
}

func (t AccountChaincode) GetAccountHis(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	key := has0xSuf(args[0])
	ab, err := stub.GetHistoryForKey(key)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	res, err := getHisResult(ab)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(Ok(res.String()).ToByte())
}

func (t AccountChaincode) QueryAddresses(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		return shim.Success(parameterErr)
	}
	name := strings.ToLower(args[0])
	query := fmt.Sprintf("{\"selector\": {\"balance.%s\": {\"$gt\": 0}}}", name)
	log.Infof(query)
	// 根据语句查询数据集
	result, err := stub.GetQueryResult(query)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	// 获取代币信息
	token, err := getToken(stub, name)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	// 解析结果集，顺便计算比例，无需再次进行循环
	addresses, err := getListResult(result, name, new(big.Int).SetInt64(token.Supply))
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}
	if len(addresses) == 0 {
		addr := &Addresses{
			Addr:    token.Owner,
			Balance: new(big.Int).SetInt64(token.Supply),
			Percent: "100%",
		}
		addresses = append(addresses, *addr)
	}
	listb, err := json.Marshal(addresses)
	if err != nil {
		return shim.Success(SysFail(err.Error()))
	}

	return shim.Success(Ok(string(listb)).ToByte())
}

type Tokens struct {
	Name   string 	`json:"name"`					// 合约名称
	Symbol string 	`json:"symbol"`					// 代币符号
	Supply string 	`json:"supply"`					// 发行总量
	Owner  string 	`json:"owner"`					// 所有人
	Status int 		`json:"status"`
}

type Token struct {
	Name        string          `json:"name"`        // 合约名称
	Symbol      string          `json:"symbol"`      // 符号，简称
	Supply      int64           `json:"supply"`      // 发行总量
	Decimals    int             `json:"decimals"`    // 代币精度
	Owner       string          `json:"owner"`       // 所有人
	Lock        bool            `json:"lock"`        // 锁定标识
	LockAccount map[string]bool `json:"lockAccount"` // 锁定用户
}

// 增加自己的代币 todo 修改完发币流程后，该操作删除
func addToken(stub shim.ChaincodeStubInterface, account *Account) error {

	if account.IsToken {
		return nil
	}

	tb, err := queryTokenList(stub, account.Addr)
	if err != nil {
		return err
	}

	var token Tokens
	err = json.Unmarshal(tb, &token)
	if err != nil {
		return err
	}

	sup, err := strconv.ParseInt(token.Supply, 10, 64)
	if err != nil {
		return err
	}

	// 由于是新建代币，顾直接赋值，无需进行计算
	account.Balance[token.Symbol] = new(big.Int).SetInt64(sup)
	// 修改标识字段
	account.IsToken = true

	return nil
}

// 验证交易签名
func verifyTransaction(msghash, signed []byte) (string,bool) {

	log.Infof("signed: %s", string(signed))

	//hash := MustDecode(string(msghash))
	sig := MustDecode(string(signed))

	log.Infof("sign: %s", string(sig))

	pubkey, err := Ecrecover(msghash, sig)
	if err != nil {
		log.Error(err.Error())
		return "", false
	}

	pubKey, _ := UnmarshalPubkey(pubkey)
	recoveredAddr := PubkeyToAddress(*pubKey)
	raddr := Bytes2Hex(recoveredAddr.Bytes())

	sig2 := sig[:len(sig)-1]
	return has0xSuf(raddr), VerifySignature(pubkey, msghash, sig2)
}

// 记录交易详情
func recordTransaction(stub shim.ChaincodeStubInterface, addr string, b []byte) error {
	log.Info(string(b))
	trans := [][]byte{[]byte("add"), []byte(addr), b}
	_, err := invokeChaincode(stub, "transaction", trans)
	return err
}

// 从代币合约获取代币信息
func getToken(stub shim.ChaincodeStubInterface, name string) (*Token, error) {
	trans := [][]byte{[]byte("getToken")}
	res, err := invokeChaincode(stub, name, trans)
	if err != nil {
		return nil, err
	}
	var token Token
	err = json.Unmarshal(res, &token)
	return &token, err
}

/*
	封装数据读写，获取状态数据库的账户信息
*/
func getAccount(stub shim.ChaincodeStubInterface, key string) (*Account, error) {
	ab, err := stub.GetState(key)
	if err != nil {
		return nil, err
	}
	var account Account
	if ab == nil {
		// 当账户数据不存在时，初始化账户数据
		account.Addr = key
		account.Balance = make(map[string]*big.Int)
		account.IsToken = false
		account.Nonce = 0
	} else {
		err = json.Unmarshal(ab, &account)
		// 新用户的结构为空，做非空判断
		if account.Balance == nil {
			account.Balance = make(map[string]*big.Int)
		}
	}
	// 拉取代币信息 todo 修改完发币流程后，该流程删除之
	if !account.IsToken {
		err = fetchToken(stub, &account)
		if err != nil {
			// 这里只记录err，不进行返回操作
			log.Error(err.Error())
		}
	}
	return &account, nil
}

// 拉取我的代币 todo 修改完发币流程后，该方法失效
func fetchToken(stub shim.ChaincodeStubInterface, account *Account) error {
	if account.IsToken {
		return nil
	}
	tb, err := fetch(stub, account.Addr)
	if err != nil {
		return err
	}

	var token Tokens
	err = json.Unmarshal(tb, &token)
	if err != nil {
		return err
	}

	sup, bs := new(big.Int).SetString(token.Supply, 10)
	if !bs {
		return err
	}

	// 由于是新建代币，顾直接赋值，无需进行计算
	account.Balance[token.Symbol] = sup
	// 修改标识字段
	account.IsToken = true

	return nil
}

// 查询我的代币 todo 修改完发币流程后，该方法失效，删除
func queryMyToken(stub shim.ChaincodeStubInterface, account *Account) error {
	if account.IsToken {
		return nil
	}
	tb, err := queryTokenList(stub, account.Addr)
	if err != nil {
		return err
	}

	if tb == nil {
		return nil
	}

	var token Tokens
	err = json.Unmarshal(tb, &token)
	if err != nil {
		return err
	}

	sup, bs := new(big.Int).SetString(token.Supply, 10)
	if !bs {
		return err
	}

	account.Balance[token.Symbol] = sup
	return nil
}

// 保存账户信息
func setAccount(stub shim.ChaincodeStubInterface, account Account) error {
	ab, err := json.Marshal(account)
	if err != nil {
		return err
	}
	err = stub.PutState(account.Addr, ab)
	return err
}

// 拉取我的代币信息（拉取会修改数据，查询不需要）todo 修改完发币流程后，该方法相对应的都要删除
func fetch(stub shim.ChaincodeStubInterface, addr string) ([]byte, error) {
	trans := [][]byte{[]byte("fetch"), []byte(addr)}
	return invokeChaincode(stub, "tokenList", trans)
}

// 查询我的代币信息
func queryTokenList(stub shim.ChaincodeStubInterface, addr string) ([]byte, error) {
	trans := [][]byte{[]byte("query"), []byte(addr)}
	return invokeChaincode(stub, "tokenList", trans)
}

// 获取日志
func getLogger(stub shim.ChaincodeStubInterface) (c *shim.ChaincodeLogger) {
	fcn, _ := stub.GetFunctionAndParameters()
	c = shim.NewLogger(fmt.Sprintf("%s.%s.%s", stub.GetChannelID(), "account", fcn))
	c.SetLevel(shim.LogDebug)
	return
}

// 调用其它链码
func invokeChaincode(stub shim.ChaincodeStubInterface, name string, trans [][]byte) ([]byte, error) {
	log.Debugf("invoke mychannel.%s, args: %s", name, trans)
	response := stub.InvokeChaincode(name, trans, "mychannel")
	if response.Status == 200 {
		return response.Payload, nil
	} else {
		return nil, errors.New(fmt.Sprintf("invoke %s chaincode error: %s", name, response.Message))
	}
}

type Ret struct {
	Code int `json:"code"`
	Data string `json:"data"`
	Message string `json:"message"`
}

func (r Ret) ToString() string {
	rb, _ := json.Marshal(r)
	return string(rb)
}

func (r Ret) ToByte() []byte {
	rb, _ := json.Marshal(r)
	return rb
}

func Ok(dat string) *Ret {
	return &Ret{
		Code:    0,
		Data:    dat,
	}
}

func Fail(code int, msg string) *Ret {
	return &Ret{
		Code:    code,
		Message: msg,
	}
}

/*
	常量以及无关数据读写的方法api
*/
var SUCCESS = Ok("success").ToByte()

var parameterErr = Fail(10000, "参数异常").ToByte()
var privateDecodeErr = Fail(10001, "私钥解密异常").ToByte()
var verifyKeyErr = Fail(10002, "签名验证错误").ToByte()
var nonceError = Fail(10003, "交易号异常").ToByte()
var tokenLockErr = Fail(10005, "通证合约被锁定").ToByte()
var balanceErr = Fail(10004, "余额不足").ToByte()
var accountLockErr = Fail(10006, "账户被锁定").ToByte()
var valueErr = Fail(10007, "不支持的交易类型").ToByte()
var permissionErr = Fail(10008, "权限不足").ToByte()
var addressError = Fail(10009, "地址异常").ToByte()
var rmbTokenLock = Fail(10012, "rmb合约被锁定").ToByte()
var vccTokenLock = Fail(10013, "vcc合约被锁定").ToByte()
var fromAccountLock = Fail(10014, "交易发送方被锁定").ToByte()
var toAccountLock = Fail(10015, "交易目标方被锁定").ToByte()
var rmbBalanceErr = Fail(10016, "余额不足（rmb）").ToByte()
var vccBalanceErr = Fail(10017, "余额不足（vcc）").ToByte()


var tokenNilErr = Fail(40001, "通证不存在").ToByte()
var addrNilErr = Fail(40002, "交易地址为空").ToByte()
var addrInTokenErr = Fail(40003, "一个地址只能发布一个通证").ToByte()

func SysFail(msg string) []byte {
	ret := Ret{
		Code:    90000,
		Message: msg,
	}
	return ret.ToByte()
}

func has0xSuf(addr string) string {
	if strings.Index(addr, "0x") != 0 {
		return strings.ToLower(addr)
	}
	return strings.ToLower(addr[2:])
}

func getHisResult(result shim.HistoryQueryIteratorInterface) (bytes.Buffer, error) {
	//由于查询的结果是一个集合，所以要将结果集转成字符串，方便传输
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false

	for result.HasNext() {

		response, err := result.Next()
		if err != nil {
			return buffer, err
		}

		if bArrayMemberAlreadyWritten {
			buffer.WriteString(",")
		}

		buffer.WriteString("{\"TxId\":\"")
		buffer.WriteString(response.TxId)
		buffer.WriteString("\",\"value\":")

		//if response.IsDelete {
		//	buffer.WriteString("null")
		//} else {
		buffer.WriteString(string(response.Value))
		//}

		buffer.WriteString(", \"Timestamp\":\"")
		buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).Format("2006-01-02 15:04:05"))
		buffer.WriteString("\"")

		buffer.WriteString(", \"IsDelete\":\"")
		buffer.WriteString(strconv.FormatBool(response.IsDelete))
		buffer.WriteString("\"")

		buffer.WriteString("}")

		//item,_:= json.Marshal(response)
		//buffer.Write(item)

		bArrayMemberAlreadyWritten = true
	}

	buffer.WriteString("]")
	return buffer, nil
}

type Addresses struct {
	Addr string `json:"addr"`
	Balance *big.Int `json:"balance"`
	Percent string `json:"percent"`
}

var zero = new(big.Int).SetInt64(10000000000)
var percentSuf = new(big.Int).SetInt64(10000)

func toPercent(per string) string {
	len := len(per)
	var s string
	if len == 2 {
		s = "0" + string([]byte(per)[:len-2]) + "." + string([]byte(per)[len-2:]) + "%"
	} else if len == 1 {
		s = "0.0" + string([]byte(per)[len-1:]) + "%"
	} else {
		s = string([]byte(per)[:len-2]) + "." + string([]byte(per)[len-2:]) + "%"
	}
	return s
}

func getListResult(resultsIterator shim.StateQueryIteratorInterface, token string, suply *big.Int) ([]Addresses, error) {

	defer resultsIterator.Close()

	var addresses []Addresses

	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}
		var account Account
		err = json.Unmarshal(queryResponse.Value, &account)
		if err != nil {
			return nil, err
		}
		addr := &Addresses{
			Addr:    account.Addr,
			Balance: account.Balance[token],
		}
		percUp := new(big.Int).Mul(account.Balance[token], percentSuf)
		percent := new(big.Int).Div(percUp, suply)
		addr.Percent = toPercent(percent.String())
		addresses = append(addresses, *addr)

	}
	return addresses, nil
}


func checkAddress(addrs ...string) bool {
	for i := range addrs {
		if !IsHexAddress(addrs[i]) {
			return false
		}
	}
	return true
}



func checkValue(value big.Int) bool {
	if value.Cmp(new(big.Int)) <= 0 {
		return false
	}
	valStr := value.String()
	if len(valStr) >= 21 {
		return false
	}
	return true
}